package com.rtsapp.server.profiling;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 性能统计类
 */
public final class Profilling {

    /**
     * 内部使用的分类ID
     */
    public interface  CategoryIds{
        int COMMAND = 1;
        int SQL = 2;
        int BENCHMARK_COMMAND = 3;
        int NETWORK = 4;
        /**
         * 请求吞吐率
         */
        int REQ_THROUGHPUT = 5;
    }

    private static Profilling instance = new Profilling( );
    public static Profilling getInstance(){
        return instance;
    }
    private Profilling(){
    }



    /**
     * 所有统计的ExecuteProfilling
     * key: 分类
     * value: 该分类下的所有时间统计
     *   ( key:id, value:ExecuteTime)
     */
    private final ConcurrentMap<Integer,ConcurrentMap<Integer, ExecuteProfilling> > allExecutes = new ConcurrentHashMap<>( );


    /**
     * 获得分类为category下真对id的执行统计
     * @param category 分类
     * @param id id
     * @return
     */
    public ExecuteProfilling getExecuteProfilling(int category, int id){

        ConcurrentMap<Integer, ExecuteProfilling> categoryExecutes = getCategoryExecutes(category);

        ExecuteProfilling executeTime = getExecuteProfilling(id, categoryExecutes);

        return executeTime;
    }

    /**
     * 将一个分类下的所有执行统计格式化成字符串输出
     * @param category
     * @return
     */
    public String formatExecuteProfillings( int category ){
        return ExecuteProfilling.formatExecuteTimeList( getExecuteProfillingList( category ) );
    }

    /**
     * 获得某一分类下的所有执行统计
     * @return
     */
    private List<ExecuteProfilling> getExecuteProfillingList(int category){
        ArrayList<ExecuteProfilling> list =  new ArrayList<>( getCategoryExecutes( category ).values() );
        Collections.sort(list);
        return list;
    }



    private ExecuteProfilling getExecuteProfilling(int id, ConcurrentMap<Integer, ExecuteProfilling> categoryExecutes) {
        ExecuteProfilling executeTime  =  categoryExecutes.get(id);
        if( executeTime == null ){
            executeTime = new ExecuteProfilling( id );

            ExecuteProfilling oldExecuteTime =  categoryExecutes.putIfAbsent(id, executeTime);
            if( oldExecuteTime != null ){
                executeTime = oldExecuteTime;
            }
        }
        return executeTime;
    }


    private ConcurrentMap<Integer, ExecuteProfilling> getCategoryExecutes(int category) {
        ConcurrentMap<Integer, ExecuteProfilling> categoryExecutes = allExecutes.get( category );

        if( categoryExecutes == null ){
            categoryExecutes = new ConcurrentHashMap<>();

            ConcurrentMap<Integer, ExecuteProfilling> oldExecutes =   allExecutes.putIfAbsent(category, categoryExecutes);
            if( oldExecutes != null ){
                categoryExecutes = oldExecutes;
            }
        }
        return categoryExecutes;
    }

}
